package
{
	import caurina.transitions.Tweener;
	import caurina.transitions.properties.CurveModifiers;
	
	import flash.display.MovieClip;
	import flash.text.TextField;
	
	import org.papervision3d.events.InteractiveScene3DEvent;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.materials.MovieMaterial;
	import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.objects.primitives.Cube;
	import org.papervision3d.objects.primitives.Plane;
	
	
	public class fileBox extends Cube
	{
		
		private var mychilds:Array = new Array(); 			//Kinder einer Box
		private var myParent:fileBox;  						//Referenz auf Elternbox
		private var open:Boolean = false;					//Flag (offen - geschlossen)
		private var interactiveModi:Boolean = true;			//Flag -> Sind die anderen Boxen interactive oder nicht
		private var openButton:Plane;						//enthält ein Plane als Button
		private var buttonText:TextField;					//bekommt die Bezeichnung des Kontens
		private static var allBoxes:Array = new Array();	//Speichert alle Kinder
		private static var stdWidth:int = 210;				//Standardbreite einer Box
		private static var stdHeight:int = 290;				//Standardhöhe einer Box
		private static var stdMargin:int = 50;				//Horizontaler Abstand zwischen den Boxen
		private static var boxLight:PointLight3D;			//Licht auf die Boxen
		
		/**
		 * Erstellt eine neue Filebox
		 * @param cParent Die Elternbox der neuen Box
		 */
		public function fileBox(cParent:fileBox = null, cLight:PointLight3D = null)
		{	
			//Licht nur einmal übernehmen
			boxLight = cLight;
			
			//Material mit zufälliger Farbe
			//Wird nachher mit Skins versehen
			var tmpMat:MaterialsList = new MaterialsList();
			tmpMat.addMaterial(
				new FlatShadeMaterial(boxLight),
				"all"
			);
		
			//Den Cube bauen			
			super(tmpMat,stdWidth,20,stdHeight, 4, 4, 4);
			
			//Link zur Elternbox
			myParent = cParent;
			
			//Alle Kinder speichern
			allBoxes.push(this);
			
			//Erst mal muss die Box enabled werden damit überhaut geklickt werden kann
			enableBox();
			
			//Bezierkurventweens erlauben
			CurveModifiers.init();
			
			//Overlay bauen
			createButton();
		}
		
		/**
		 * erstellt die 2D Buttons auf dem Cube
		 */
		private function createButton():void{
			
			var tmpMc:MovieClip = new MovieClip();
			
			with(tmpMc){
				graphics.beginFill(0xff0000);
				graphics.drawRoundRect(0,0,180,30,10,0);
				graphics.endFill();
			}
			
			buttonText = new TextField();
			buttonText.textColor = 0xffffff;
			buttonText.height = 30;
			tmpMc.addChild(buttonText);
			
			var mcMat:MovieMaterial = new MovieMaterial(tmpMc);
			
			
			openButton = new Plane(mcMat,180,30,4,4);
			openButton.moveBackward(40);
			addChild(openButton);
		}
		
		/**
		 * Die Box bekommt das Over-Event und das Material wird auf Interactive gesetzt.
		 * Die Box wird rot gefärbt.
		 */
		public function enableBox():void{
			//Alle unnötigen Events entfernen
			this.removeEventListener(InteractiveScene3DEvent.OBJECT_CLICK,toggleView);
			this.removeEventListener(InteractiveScene3DEvent.OBJECT_OUT,enableInteractive);
			
			//Es ist nur das OverEvent wichtig
			this.addEventListener(InteractiveScene3DEvent.OBJECT_OVER,disableInteractive);
			
			//Interactivität einschalten
			this.getMaterialByName("back").interactive = true;
			
			//Box färben
			//this.getMaterialByName("back").fillColor = 0xff0000;
		}
		
		/**
		 * Der Box werden alle Listener weg genommen und das Material wir inaktiv
		 */
		public function disableBox():void{
			//Alle Events entfernen
			this.removeEventListener(InteractiveScene3DEvent.OBJECT_OVER,disableInteractive);
			this.removeEventListener(InteractiveScene3DEvent.OBJECT_OUT,enableInteractive);
			
			//Material muss nicht mehr interactive sein
			this.getMaterialByName("back").interactive = false;
			
			//Seite färben
			//this.getMaterialByName("back").fillColor = 0xcccccc;
		}
		
		/**
		 * Um ein bisschen mehr Performence heraus zu kitzeln verlieren
		 * alle Boxen Ihre Events und das InteractiveMaterial. Ausser die Box auf der
		 * man gerade mit der Maus steht. Diese aktive Box bekommt einen Out und Clicklistener.
		 */
		private function disableInteractive(e:InteractiveScene3DEvent):void{
			
			//Wenn bereits disabled
			if(interactiveModi == false){
				//Sofort raus
				return;
			}
			//Flag setzen -> Boxen sind disabled
			interactiveModi = false;
			
			//Alle Boxen durchlaufen
			for each(var tmpBox:fileBox in allBoxes){
				//Wenn es nicht die Box ist auf der man sich gerade befindet
				if(tmpBox != this){
					//Box disablen
					tmpBox.disableBox();
				}
				else{
					//Der aktiven Box den Klick und OutEvent geben
					tmpBox.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK,toggleView);	
					tmpBox.addEventListener(InteractiveScene3DEvent.OBJECT_OUT,enableInteractive);
				}
			}
		}
		
		/**
		 * Wenn die Maus gerade nicht über einer Box steht müssen wieder alle Boxen
		 * darauf achten, ob sie von der Maus gestreift werden. Also werden alle Boxen
		 * mit einem Over-Listener ausgestattet.
		 * @param e auslösendes 3D ClickEvent
		 */
		private function enableInteractive(e:InteractiveScene3DEvent):void{
			
			//Wenn die Box bereits auf interaktiv ist
			if(interactiveModi == true){
				//Sofort abbrechen
				return;
			}
			
			//Damit nicht immer alle 
			interactiveModi = true;
			
			//Alle Boxen enablen
			for each(var tmpBox:fileBox in allBoxes){
				tmpBox.enableBox();
			}
		}

		/**
		 * Ausgelöst durch das anklicken der Box
		 * @param e auslösendes 3D ClickEvent
		 */
		private function toggleView(e:InteractiveScene3DEvent):void{
			
			
			//Feststellen ob und wenn ja in welcher Reihenfolge ein "Backtween" nötig ist
			if(myParent != null){
				//Start der Rekursion
				var BackTween:Array = myParent.getTweenRoute();
				
				//Und wenn nötig zurück tweenen
				for each(var routeBox:fileBox in BackTween) {
						routeBox.backTween();
				}
			} 
			
			
			switch(open){
				case true: //Zuklappen
					break;
					
				case false: //Aufklappen
					open = true;
					
					var xmlget:xmlGetter = new xmlGetter(this,responseTest,1);
					
					break;
			}
			

		}
		
		/**
		 * Antwort der Datenbank. Hier werden die Kinder erstellt und 
		 * getweent.
		 */
		public function responseTest(response:XML):void{
			
			//Anzahl von Kindern
			var ChildAnz:int = response.studiengang.length();
			
			//Gesamtbreite aller Kinder = Die Zufallszahl mal die Standardbreite
			var widthChilds:int = ChildAnz * stdWidth;
			
			//Bei mehr als einem Nachkommen -> Es gibt Abstände zwischen den Boxen
			if(ChildAnz > 1){
				//Zur bereits errechneten Gesamtbreite kommt noch der Abstand zwischen den Boxen
				widthChilds += (ChildAnz - 1) * stdMargin;						
			}
			
			//Erste Position des ERSTEN Kindes errechnen
			var startPoint:int = widthChilds / 2 * -1;
			
			for(var i:int = 0; i < ChildAnz; i++){
				//Neue Box erstellen
				var tmpBox:fileBox = new fileBox(this);
				
				//Bezeichnung draufbauen und festschrauben
				tmpBox.buttonText.appendText("Hallo"+response.studiengang[i].@name);

				//An die richtige Stelle tweenen
				Tweener.addTween(
					tmpBox,
					{
						x:tmpBox.x + startPoint,
						y:tmpBox.y + (stdMargin + stdHeight) * -1,
						z:tmpBox.z,
						time:2
					}
				);
				
				//Zuerst hinter dem Elternbox erstellen
				tmpBox.moveForward(50 * (i + 1));
				
				//Das Kind in sich selber einbetten
				addChild(tmpBox);
				
				//Als eingenes Kind abspeichern
				mychilds.push(tmpBox);
				
				//die Startposition für das nächste Geschwisterchen aufrechnen
				startPoint += stdWidth + stdMargin;
			}
			
			
			//text.appendText(response.studiengang[i].@name);
			
		} 
		
		/**
		 * Stellt die Route der offenen Kinder her. Das zuletzt geöffnete Kind ist das erste im
		 * zurück gegebnen Array
		 */
		public function getTweenRoute():Array{
			//Suche nach einer geöffneten Box
			for each(var box:fileBox in mychilds) {
				//Es gibt noch eine offene
				if(box.open == true){
					
					//In der geöffneten Reihe wieder nach öffenen Boxen Suchen
					//Rekursion
					var BackTween:Array = box.getTweenRoute();
					
					//Nach Ende der Rekursion sich selber ans Ende der Route anhängen
					BackTween.push(box);
					
					//Die bisherige Route zurückgeben
					return BackTween;
				}		
			}
			
			//Keine offenen Boxen gefunden
			//Hier ist das Ende der Rekursion -> Es wird die BackTweenRoute erstellt und
			//zurück gegeben
			return new Array();
		}
		
		/**
		 * Wird für jedes Element der Backtween aufgerufen
		 * Alle offenen Kinder werden auf die 0,0,0 Position zurückj getweent
		 */
		public function backTween():void{
			for each(var box:fileBox in mychilds) {
				Tweener.addTween(box,{x:0,y:0,z:50,time:1,
					onComplete:function():void{
						box.removeMe();
					}	
				});	
			}
		}
		
		/**
		 * Entfernt den Clickevent in allen Kindern
		 */
		public function disableChilds():void{
			for each(var box:fileBox in mychilds) {
				box.removeEvent();		
			}
		}
		
		/**
		 * Entfernt den Clickevent dieses Elements
		 * Zur optischen Unterstützung leicht drehen
		 */
		public function removeEvent():void{
			this.removeEventListener(InteractiveScene3DEvent.OBJECT_CLICK,toggleView);
			this.yaw(10);
		}
		
		/**
		 * Zerstört eine 3D Box
		 */
		public function removeMe():void{
			/*
			
			//Aus der Liste der Kinder entfernen
			myParent.mychilds.splice(myParent.mychilds.indexOf(this),1);
			
			//Wieder auf geschlossen setzen
			myParent.open = false;
			*/
			
			//Aus der Liste aller Boxen entfernen
			allBoxes.splice(allBoxes.indexOf(this),1);
			
			//Kind ausblenden
			myParent.removeChild(this);
			
			getMaterialByName("back").fillColor = 0x00ff00;
		}
		
		/**
		 * Tween ein 3D Objekt mit linearer Geschwindigkeit an eine Position
		 * @param cx Zielposition x im 3D Raum
		 * @param cy Zielposition y im 3D Raum
		 * @param cz Zielposition z im 3D Raum
		 * @param i  Faktor für die Dauer des Tweens
		 */
		public function tweenTo(cx:int,cy:int,cz:int,i:int):void{
			Tweener.addTween(this,{x:cx,y:cy,z:cz,time:1+(i/3)});
		}

	}
}